package com.quan.admin.web.controller;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.quan.admin.commons.vo.SysUserVo;
import com.quan.admin.commons.constant.RabbitMQConstant;
import com.quan.admin.entity.SysPermission;
import com.quan.admin.entity.SysRole;
import com.quan.admin.entity.SysUser;
import com.quan.admin.entity.SysUserRole;
import com.quan.admin.service.SysRolePermissionService;
import com.quan.admin.service.SysUserRoleService;
import com.quan.admin.service.SysUserService;
import com.quan.commons.core.bean.R;
import com.quan.commons.core.biz.support.MyBaseController;
import com.quan.commons.core.constant.CommonsConstant;
import com.quan.commons.core.properties.SystemValueProperties;
import com.quan.commons.core.utils.*;
import com.quan.commons.log.annotation.SysLog;
import com.quan.commons.tools.mail.vo.MailBean;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 系统-用户
 * @author yhaoquan
 * @email yhaoquan@163.com
 * @date 2020-08-03 20:32:03
 */
@Slf4j
@Api(tags = "系统-用户")
@RestController
@RequestMapping("sysuser")
public class SysUserController extends MyBaseController {

    @Autowired
    private SysUserService service;

    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Autowired
    private SysRolePermissionService sysRolePermissionService;

    @Autowired
    private SystemValueProperties properties;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 自定义分页列表
     * @param entity
     * @return
     */
    @GetMapping(value = "selectMyPage")
    public Object selectMyPage(SysUser entity) {
        IPage<SysUser> page = this.service.selectMyPage(new PageUtils(request), entity);
        return R.ok().put("data", page);
    }

    /**
     * 分页列表
     * @param entity
     * @return
     */
    @SysLog("查询用户列表")
    @GetMapping(value = "page")
    public Object page(SysUser entity) {
        IPage<SysUser> page = this.service.selectPage(new PageUtils(request), entity);
        return R.ok().put("data", page);
    }

    /**
     * 列表
     * @param entity
     * @return
     */
    @GetMapping(value = "list")
    public Object list(SysUser entity) {
        List<SysUser> list = this.service.list(new PageUtils(request), entity);
        return R.ok().put("data", list);
    }


    /**
     * 信息
     * @param {id}
     * @return
     */
    @GetMapping("/info/{id}")
    public R info(@PathVariable("id") Long id) {
        SysUser sysUser = this.service.getById(id);

        return R.ok().put("data", sysUser);
    }

    /**
     * 保存
     * @param entity
     * @return
     */
    @PostMapping("save")
    public R save(@Valid @RequestBody SysUser entity) {
        if (this.service.hasFieldValue("username", entity.getUsername())) {
            return R.failure("该用户名已存在【"+entity.getUsername()+"】");
        }
        if (this.service.hasFieldValue("mobile", entity.getMobile())) {
            return R.failure("该手机号已存在【"+entity.getMobile()+"】");
        }
        if (this.service.hasFieldValue("email", entity.getEmail())) {
            return R.failure("该邮箱地址已存在【"+entity.getEmail()+"】");
        }

        this.service.save(entity);

        return R.ok();
    }

    /**
     * 修改
     * @param entity
     * @return
     */
    @PostMapping("update")
    public R update(@Valid @RequestBody SysUser entity) {

        if (this.service.hasFieldValueForUpdate(entity.getId(), "username", entity.getUsername())) {
            return R.failure("该用户名已存在【"+entity.getUsername()+"】");
        }
        if (this.service.hasFieldValueForUpdate(entity.getId(), "mobile", entity.getMobile())) {
            return R.failure("该手机号已存在【"+entity.getMobile()+"】");
        }
        if (this.service.hasFieldValueForUpdate(entity.getId(), "email", entity.getEmail())) {
            return R.failure("该邮箱地址已存在【"+entity.getEmail()+"】");
        }

        this.service.updateById(entity);

        return R.ok();
    }

    /**
     * 删除
     * @param params idList: [1,2,3]
     * @return
     */
    @PostMapping("delete")
    public R delete(@RequestBody Map<String, Object> params) {
        if (null != params && !params.isEmpty()) {
            List<Long> idList = JSON.parseArray(params.get("idList").toString(), Long.class);
            this.service.removeByIds(idList);
            return R.ok();
        } else {
            return R.failure();
        }
    }


    /**
     * 获取用户信息
     * @param token
     * @return
     */
    @GetMapping("getUserInfo")
    public R delete(@RequestParam(required = true) String token) {
        // 用户信息
        SysUser user = this.service.getUserInfo(token);

        // 用户角色
        final List<SysRole> roles = this.service.getUserRoles(user.getId());

        // 获取用户权限
        final List<SysPermission> permissions = this.service.getUserPermissions(user.getId());

        // UI访问权限列表
        List<String> access = new ArrayList<String>();
        for (SysPermission permission : permissions) {
            access.add(permission.getPermission());
        }

        return R.ok().put("user", user).put("roles", roles).put("access", access);
    }

    /**
     * 用户登录
     * @param vo
     * @return
     */
    @PostMapping("login")
    public R login(@RequestBody SysUserVo vo) {
        final String token = this.service.login(vo);
        return R.ok("登录成功").put("token", token);
    }

    /**
     * 用户登出
     * @return
     */
    @SysLog(type = CommonsConstant.LogTypeEnums.LOGOUT, value = "用户登出")
    @GetMapping("/logout")
    public boolean logout() {
        String token = this.request.getHeader("token");

        // Token为空，缓存中已没有改用户数据
        if (null == token || "".equals(token.trim())) {
            return true;
        }

        final String userId = JwtUtils.getUserId(token, this.properties.getJwt().getSecret());
        if (null != userId) {
            this.redisUtils.del(CommonsConstant.RedisPrefix.SSO_TOKEN + ":" + userId);
            return true;
        } else {
            log.info("Token解析失败");
            return false;
        }
    }


    /**
     * 根据用户ID加载用户对应的角色
     * @param userId
     * @return
     */
    @GetMapping(value = "/getRolesByUserId/{userId}")
    public Object getRolesByUserId(@PathVariable String userId) {
        return R.ok().put("data", this.sysUserRoleService.getRolesByUserId(userId));
    }

    /**
     * 根据用户角色ID获取用户对应的权限关联关系数据
     * @param roleIds
     * @return
     */
    @RequestMapping(value = "/getRolesPermitByUserRoleIds")
    public Object getRolesPermitByUserRoleIds(@RequestBody List<Long> roleIds) {
        return R.ok().put("data", this.sysRolePermissionService.getPermissionByRoleIds(roleIds));
    }

    /**
     * 添加、修改、删除用户与角色关联
     * @param map {"userId": 1, "roles": [1, 2]}
     * @return
     */
    @PostMapping("/setUserRole")
    public Object setUserRole(@RequestBody Map<String, Object> map) {

        String userId = map.get("userId").toString();
        JSONArray parseArray = JSON.parseArray(map.get("roles").toString());

        if (null != userId) {
            this.sysUserRoleService.deleteByUserId(userId);

            if (!parseArray.isEmpty()) {
                List<SysUserRole> list = new ArrayList<>();
                for (int i = 0; i < parseArray.size(); i++) {

                    SysUserRole entity = new SysUserRole();
                    entity.setUserId(Long.parseLong(userId));
                    entity.setRoleId(parseArray.getInteger(i));
                    list.add(entity);
                }
                this.sysUserRoleService.saveBatch(list);
            }
        }

        return R.ok();
    }

    /**
     * 重置用户登陆密码为[123456]
     * @param params idList:["1","2"]
     * @return
     */
    @PostMapping("/batchResetPassword")
    public Object batchResetPassword(@RequestBody Map<String, Object> params) {
        if (null != params && !params.isEmpty()) {
            List<Long> idList = JSON.parseArray(params.get("idList").toString(), Long.class);
            boolean flag = this.service.batchResetPassword(idList);
            if (flag) {
                return R.ok();
            } else {
                return R.failure("重置用户登陆密码失败：[ " + idList + " ]");
            }
        }
        return R.failure("请选项需要重置用户登陆密码的记录");
    }


    /**
     * 修改个人登录密码
     * @param vo
     * @return
     */
    @ApiOperation(value = "修改个人登录密码")
    @PostMapping(value = "updateMyPassword")
    public Object updateMyPassword(@RequestBody SysUserVo vo) {
        try {
            if (StringUtils.isBlank(vo.getOldPassword())) {
                return R.failure("原密码不能为空");
            }
            if (StringUtils.isBlank(vo.getNewPassword())) {
                return R.failure("新密码不能为空");
            }
            this.service.updatePassword(vo.getId(), vo.getOldPassword(), vo.getNewPassword());
            return R.ok();
        } catch (RuntimeException e) {
            return R.failure(e.getMessage());
        }
    }

    /**
     * 修改个人基本信息
     * @param entity
     * @return
     */
    @ApiOperation(value = "修改个人基本信息")
    @PostMapping(value = "updateMyInfo")
    public Object updateMyInfo(@RequestBody SysUser entity) {
        if (StringUtils.isBlank(entity.getRealname())) {
            return R.failure("姓名不能为空");
        }
        if (StringUtils.isBlank(entity.getEmail())) {
            return R.failure("邮件地址不能为空");
        }
        if (StringUtils.isBlank(entity.getMobile())) {
            return R.failure("手机号码不能为空");
        }

        entity.setPassword(null);
        entity.setSalt(null);
        this.service.updateById(entity);

        return R.ok();
    }

    /**
     * 忘记密码，进行邮件通知
     * @param entity
     * @return
     */
    @PostMapping(value = "forgetPasswordSendMail")
    public Object forgotPasswordSendMail(@RequestBody SysUser entity) {
        if (StringUtils.isBlank(entity.getEmail())) {
            return R.failure("邮件地址不能为空");
        }

        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<SysUser>();
        queryWrapper.eq("email", entity.getEmail());
        SysUser user = this.service.getOne(queryWrapper, false);
        if (null == user) {
            return R.failure("邮箱地址不存在！");
        }

        // 修改密码凭证
        String resetPwdToken = RandomUtil.randomNumbers(4);
        this.redisUtils.set(CommonsConstant.RedisPrefix.RESET_PWD_TOKEN + ":" + resetPwdToken, user.getId() + "", 60 * 30);

        // 发送短信或邮件告知用户账号和密码
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("subject", "密码找回");
        map.put("resetPwdToken", resetPwdToken);

        MailBean mailBean = new MailBean();
        mailBean.setTo(entity.getEmail());
        mailBean.setSubject(map.get("subject").toString());
        mailBean.setTemplateLocation("mail/forget_password.html");
        mailBean.setTemplateData(map);

        // 发送消息给MQ
        this.rabbitTemplate.convertAndSend(RabbitMQConstant.SYSTEM_EVENT_EXCHANGE, RabbitMQConstant.SYSTEM_ROUTING_KEY_MAIL, mailBean);

        return R.ok("邮件已发送");
    }

    /**
     * 用户找回密码，重新修改密码
     * @param vo
     * @return
     */
    @ApiOperation(value = "用户找回密码，重新修改密码")
    @PostMapping(value = "forgetPasswordByUpdate")
    public Object forgetPasswordByUpdate(@RequestBody SysUserVo vo) {
        if (StringUtils.isBlank(vo.getPassword())) {
            return R.failure("密码不能为空");
        }

        final String userId = this.redisUtils.get(CommonsConstant.RedisPrefix.RESET_PWD_TOKEN + ":" + vo.getToken());
        if (StringUtils.isNotBlank(userId)) {
            final SysUser user = this.service.getById(userId);
            user.setSalt(RandomUitl.uuid());
            user.setPassword(PasswordUtils.encodePassword(vo.getPassword(), user.getSalt()));
            final boolean b = this.service.updateById(user);
            if (b) {
                this.redisUtils.del(CommonsConstant.RedisPrefix.RESET_PWD_TOKEN + ":" + vo.getToken());
            }
        } else {
            return R.failure("修改密码凭证失效，请重新申请找回密码！");
        }

        return R.ok("密码修改成功，请重新登陆");
    }


}
